﻿using System;
using System.Net;
using System.Threading;
using Spring.Net;
using Spring.Net.Rtp;
using Spring.Net.Rtp.AppleMidi;
using Spring.Net.Rtp.Interop;

namespace SendNotes
{
    // http://anonsvn.wireshark.org/wireshark/trunk/epan/dissectors/packet-applemidi.c AppleMIDI Session Negotiation
    // http://www.cs.berkeley.edu/~lazzaro/rtpmidi/
    // http://www.rfc-editor.org/rfc/rfc6295.txt RFC6295 RTP-MIDI
    // http://www.ietf.org/rfc/rfc3550.txt RFC3550 RTP

    public class Program
    {
        private static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("Please, specify a valid network port number.");
                Environment.Exit(1);
            }

            var port = 5083;
            if (!Int32.TryParse(args[0], out port))
            {
                Console.WriteLine("Please, specify a valid numeric value (1024-65535) for a port number.");
                Environment.Exit(1);
            }

            // Register common services

            var clockService = new RtpMidiClock(RtpHelper.GetRandomUInt32(0x54535450 /* TSTP */), 44100);

            var serviceProvider = ServiceProvider.GetProvider();
            serviceProvider.RegisterService<IProvideClockService>(clockService);

            // proceed

            Timer timer = null;

            using (var listener = new AppleMidiSessionListener("SendNotes", IPAddress.Any, 5083))
            {
                listener.OnSessionCreated +=
                    (sender, e) =>
                        {
                            Console.WriteLine("====== SESSION CREATED =========");

                            timer =
                                new Timer(unused =>
                                              {
                                                  timer.Change(Timeout.Infinite, Timeout.Infinite);
                                                  e.Session.SendCommand(new byte[] {0x91, 0x3F, 0x3F,});
                                                  Console.WriteLine(">> TRANSMITTING: [Channel: 1] Note On (C4, v=63)");
                                                  Thread.Sleep(350);
                                                  e.Session.SendCommand(new byte[] {0x81, 0x3F, 0x3F,});
                                                  Console.WriteLine(">> TRANSMITTING: [Channel: 1] Note Off (C4, v=63)");
                                                  timer.Change(8000 /* ms */, 3000 /* ms */);
                                              }, null, Timeout.Infinite, Timeout.Infinite);
                            timer.Change(8000 /* ms */, 3000 /* ms */);
                        };
                listener.OnSessionClosing +=
                    (sender, e) =>
                        {
                            timer.Change(Timeout.Infinite, Timeout.Infinite);
                            Console.WriteLine("====== CLOSING SESSION =========");
                        };

                listener.Start();

                Console.WriteLine("Please, press ENTER to shutdown.");
                Console.ReadLine();

                listener.Stop();

                Console.WriteLine("Listener stopped.");
            }
        }
    }
}